๋จ์, ํตํฉ, ์๋ํฌ์๋ ํ ์คํธ์ ์์ธ ๋น๊ต๋ฅผ ํตํด ์๋ฐ์คํฌ๋ฆฝํธ ํ ์คํธ๋ฅผ ๋ง์คํฐํ์ธ์. ๊ฒฌ๊ณ ํ ์ํํธ์จ์ด๋ฅผ ์ํด ๊ฐ ์ ๊ทผ ๋ฐฉ์์ ์ธ์ ์ด๋ป๊ฒ ์ฌ์ฉํด์ผ ํ๋์ง ๋ฐฐ์ฐ์ธ์.
์๋ฐ์คํฌ๋ฆฝํธ ํ ์คํธ: ๋จ์ vs. ํตํฉ vs. E2E - ์ข ํฉ ๊ฐ์ด๋
ํ ์คํธ๋ ์ํํธ์จ์ด ๊ฐ๋ฐ์ ์ค์ํ ์ธก๋ฉด์ผ๋ก, ์๋ฐ์คํฌ๋ฆฝํธ ์ ํ๋ฆฌ์ผ์ด์ ์ ์ ๋ขฐ์ฑ, ์์ ์ฑ, ์ ์ง๋ณด์์ฑ์ ๋ณด์ฅํฉ๋๋ค. ์ฌ๋ฐ๋ฅธ ํ ์คํธ ์ ๋ต์ ์ ํํ๋ ๊ฒ์ ๊ฐ๋ฐ ํ๋ก์ธ์ค์ ํ์ง๊ณผ ํจ์จ์ฑ์ ์๋นํ ์ํฅ์ ๋ฏธ์น ์ ์์ต๋๋ค. ์ด ๊ฐ์ด๋๋ ์๋ฐ์คํฌ๋ฆฝํธ ํ ์คํธ์ ์ธ ๊ฐ์ง ๊ธฐ๋ณธ ์ ํ์ธ ๋จ์ ํ ์คํธ, ํตํฉ ํ ์คํธ, ์๋ํฌ์๋(E2E) ํ ์คํธ์ ๋ํ ํฌ๊ด์ ์ธ ๊ฐ์๋ฅผ ์ ๊ณตํฉ๋๋ค. ๊ฐ ํ ์คํธ์ ์ฐจ์ด์ , ์ด์ , ์ค์ ์ ์ฉ ์ฌ๋ก๋ฅผ ์ดํด๋ณด๊ณ ํ ์คํธ ์ ๊ทผ ๋ฐฉ์์ ๋ํด ์ ๋ณด์ ์ ๊ฐํ ๊ฒฐ์ ์ ๋ด๋ฆด ์ ์๋๋ก ๋๊ฒ ์ต๋๋ค.
ํ ์คํธ๋ ์ ์ค์ํ๊ฐ?
๊ฐ ํ ์คํธ ์ ํ์ ์ธ๋ถ ์ฌํญ์ ์ดํด๋ณด๊ธฐ ์ ์, ์ผ๋ฐ์ ์ผ๋ก ํ ์คํธ์ ์ค์์ฑ์ ๋ํด ๊ฐ๋ตํ ๋ ผ์ํด ๋ณด๊ฒ ์ต๋๋ค.
- ์กฐ๊ธฐ ๋ฒ๊ทธ ๋ฐ๊ฒฌ: ๊ฐ๋ฐ ์๋ช ์ฃผ๊ธฐ ์ด๊ธฐ์ ๋ฒ๊ทธ๋ฅผ ์๋ณํ๊ณ ์์ ํ๋ ๊ฒ์ด ํ๋ก๋์ ํ๊ฒฝ์์ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๋ ๊ฒ๋ณด๋ค ํจ์ฌ ์ ๋ ดํ๊ณ ์ฝ์ต๋๋ค.
- ์ฝ๋ ํ์ง ํฅ์: ํ ์คํธ๋ฅผ ์์ฑํ๋ฉด ๋ ๊นจ๋ํ๊ณ , ๋ชจ๋ํ๋๊ณ , ์ ์ง๋ณด์ํ๊ธฐ ์ฌ์ด ์ฝ๋๋ฅผ ์์ฑํ๋๋ก ์ฅ๋ ค๋ฉ๋๋ค.
- ์ ๋ขฐ์ฑ ๋ณด์ฅ: ํ ์คํธ๋ ์ฝ๋๊ฐ ๋ค์ํ ์กฐ๊ฑด์์ ์์๋๋ก ์๋ํ๋ค๋ ํ์ ์ ์ค๋๋ค.
- ๋ฆฌํฉํ ๋ง ์ด์ง: ํฌ๊ด์ ์ธ ํ ์คํธ ์ค์ํธ๊ฐ ์์ผ๋ฉด ๋ชจ๋ ๋ฆฌ๊ทธ๋ ์ (ํ๊ท)์ ์ ์ํ๊ฒ ์๋ณํ ์ ์๋ค๋ ๊ฒ์ ์๊ธฐ ๋๋ฌธ์ ๋ ํฐ ์์ ๊ฐ์ ๊ฐ์ง๊ณ ์ฝ๋๋ฅผ ๋ฆฌํฉํ ๋งํ ์ ์์ต๋๋ค.
- ํ์ ๊ฐ์ : ํ ์คํธ๋ ์ฝ๋๊ฐ ์ด๋ป๊ฒ ์ฌ์ฉ๋์ด์ผ ํ๋์ง๋ฅผ ๋ณด์ฌ์ฃผ๋ ๋ฌธ์ ์ญํ ์ ํฉ๋๋ค.
๋จ์ ํ ์คํธ
๋จ์ ํ ์คํธ๋ ๋ฌด์์ธ๊ฐ?
๋จ์ ํ ์คํธ๋ ์ฝ๋์ ๊ฐ๋ณ ๋จ์ ๋๋ ๊ตฌ์ฑ ์์๋ฅผ ๊ฒฉ๋ฆฌํ์ฌ ํ ์คํธํ๋ ๊ฒ์ ํฌํจํฉ๋๋ค. "๋จ์"๋ ์ผ๋ฐ์ ์ผ๋ก ํจ์, ๋ฉ์๋ ๋๋ ํด๋์ค๋ฅผ ์๋ฏธํฉ๋๋ค. ๋ชฉํ๋ ๊ฐ ๋จ์๊ฐ ์์คํ ์ ๋ค๋ฅธ ๋ถ๋ถ๊ณผ ๋ ๋ฆฝ์ ์ผ๋ก ์๋๋ ๊ธฐ๋ฅ์ ์ฌ๋ฐ๋ฅด๊ฒ ์ํํ๋์ง ํ์ธํ๋ ๊ฒ์ ๋๋ค.
๋จ์ ํ ์คํธ์ ์ด์
- ์กฐ๊ธฐ ๋ฒ๊ทธ ๋ฐ๊ฒฌ: ๋จ์ ํ ์คํธ๋ ๊ฐ๋ฐ ์ด๊ธฐ ๋จ๊ณ์์ ๋ฒ๊ทธ๋ฅผ ์๋ณํ์ฌ ์์คํ ์ ๋ค๋ฅธ ๋ถ๋ถ์ผ๋ก ์ ํ๋๋ ๊ฒ์ ๋ฐฉ์งํ๋ ๋ฐ ๋์์ด ๋ฉ๋๋ค.
- ๋ ๋น ๋ฅธ ํผ๋๋ฐฑ ๋ฃจํ: ๋จ์ ํ ์คํธ๋ ์ผ๋ฐ์ ์ผ๋ก ์คํ ์๋๊ฐ ๋นจ๋ผ ์ฝ๋ ๋ณ๊ฒฝ์ ๋ํ ์ ์ํ ํผ๋๋ฐฑ์ ์ ๊ณตํฉ๋๋ค.
- ๊ฐ์ ๋ ์ฝ๋ ๋์์ธ: ๋จ์ ํ ์คํธ๋ฅผ ์์ฑํ๋ฉด ๋ชจ๋์์ด๊ณ ํ ์คํธ ๊ฐ๋ฅํ ์ฝ๋๋ฅผ ์์ฑํ๋๋ก ์ฅ๋ ค๋ฉ๋๋ค.
- ๋ ์ฌ์ด ๋๋ฒ๊น : ๋จ์ ํ ์คํธ๊ฐ ์คํจํ๋ฉด ๋ฌธ์ ์ ์์ธ์ ๋น๊ต์ ์ฝ๊ฒ ์ฐพ์๋ผ ์ ์์ต๋๋ค.
- ๋ฌธ์ํ: ๋จ์ ํ ์คํธ๋ ๊ฐ๋ณ ๋จ์๊ฐ ์ด๋ป๊ฒ ์ฌ์ฉ๋์ด์ผ ํ๋์ง๋ฅผ ๋ณด์ฌ์ฃผ๋ ์ด์์๋ ๋ฌธ์ ์ญํ ์ ํฉ๋๋ค.
๋จ์ ํ ์คํธ ๋ชจ๋ฒ ์ฌ๋ก
- ํ ์คํธ ์ฐ์ ์์ฑ(ํ ์คํธ ์ฃผ๋ ๊ฐ๋ฐ - TDD): ์ฝ๋๋ฅผ ์์ฑํ๊ธฐ ์ ์ ํ ์คํธ๋ฅผ ๋จผ์ ์์ฑํ์ธ์. ์ด๋ ์๊ตฌ์ฌํญ์ ์ง์คํ๊ณ ์ฝ๋๊ฐ ํ ์คํธ ๊ฐ๋ฅํ๋๋ก ๋ณด์ฅํ๋ ๋ฐ ๋์์ด ๋ฉ๋๋ค.
- ๊ฒฉ๋ฆฌ๋ ํ ์คํธ: ๋ชจํน(mocking) ๋ฐ ์คํฐ๋น(stubbing)๊ณผ ๊ฐ์ ๊ธฐ์ ์ ์ฌ์ฉํ์ฌ ํ ์คํธ ๋์ ๋จ์๋ฅผ ์์กด์ฑ์ผ๋ก๋ถํฐ ๊ฒฉ๋ฆฌํ์ธ์.
- ๋ช ํํ๊ณ ๊ฐ๊ฒฐํ ํ ์คํธ ์์ฑ: ํ ์คํธ๋ ์ดํดํ๊ณ ์ ์ง๋ณด์ํ๊ธฐ ์ฌ์์ผ ํฉ๋๋ค.
- ์ฃ์ง ์ผ์ด์ค ํ ์คํธ: ๊ฒฝ๊ณ ์กฐ๊ฑด๊ณผ ์ ํจํ์ง ์์ ์ ๋ ฅ์ ํ ์คํธํ์ฌ ์ฝ๋๊ฐ ์ด๋ฅผ ์ ์์ ์ผ๋ก ์ฒ๋ฆฌํ๋์ง ํ์ธํ์ธ์.
- ํ ์คํธ ์๋ ์ ์ง: ๋๋ฆฐ ํ ์คํธ๋ ๊ฐ๋ฐ์๋ค์ด ์์ฃผ ์คํํ๋ ๊ฒ์ ๊บผ๋ฆฌ๊ฒ ๋ง๋ค ์ ์์ต๋๋ค.
- ํ ์คํธ ์๋ํ: ํ ์คํธ๋ฅผ ๋น๋ ํ๋ก์ธ์ค์ ํตํฉํ์ฌ ๋ชจ๋ ์ฝ๋ ๋ณ๊ฒฝ ์ ์๋์ผ๋ก ์คํ๋๋๋ก ํ์ธ์.
๋จ์ ํ ์คํธ ๋๊ตฌ ๋ฐ ํ๋ ์์ํฌ
๋จ์ ํ ์คํธ๋ฅผ ์์ฑํ๊ณ ์คํํ๋ ๋ฐ ๋์์ด ๋๋ ์ฌ๋ฌ ์๋ฐ์คํฌ๋ฆฝํธ ํ ์คํธ ํ๋ ์์ํฌ๊ฐ ์์ต๋๋ค. ์ธ๊ธฐ ์๋ ๋ช ๊ฐ์ง ์ต์ ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
- Jest: ํ์ด์ค๋ถ์ด ๋ง๋ ์ธ๊ธฐ ์๊ณ ๋ค์ฌ๋ค๋ฅํ ํ ์คํธ ํ๋ ์์ํฌ์ ๋๋ค. ์ ๋ก ๊ตฌ์ฑ ์ค์ , ๋ด์ฅ๋ ๋ชจํน ๋ฐ ์ฝ๋ ์ปค๋ฒ๋ฆฌ์ง ๋ฆฌํฌํธ๊ฐ ํน์ง์ ๋๋ค. Jest๋ React, Vue, Angular ๋ฐ Node.js ์ ํ๋ฆฌ์ผ์ด์ ํ ์คํธ์ ์ ํฉํฉ๋๋ค.
- Mocha: ํ ์คํธ๋ฅผ ์์ฑํ๊ณ ์คํํ๊ธฐ ์ํ ํ๋ถํ ๊ธฐ๋ฅ ์ธํธ๋ฅผ ์ ๊ณตํ๋ ์ ์ฐํ๊ณ ํ์ฅ ๊ฐ๋ฅํ ํ ์คํธ ํ๋ ์์ํฌ์ ๋๋ค. Chai(์ด์ค์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ) ๋ฐ Sinon.JS(๋ชจํน ๋ผ์ด๋ธ๋ฌ๋ฆฌ)์ ๊ฐ์ ์ถ๊ฐ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๊ฐ ํ์ํฉ๋๋ค.
- Jasmine: ์ฌ์์ฒ๋ผ ์ฝํ๋ ํ ์คํธ ์์ฑ์ ๊ฐ์กฐํ๋ ํ๋ ์ฃผ๋ ๊ฐ๋ฐ(BDD) ํ๋ ์์ํฌ์ ๋๋ค. ๋ด์ฅ๋ ์ด์ค์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ํฌํจํ๋ฉฐ ๋ชจํน์ ์ง์ํฉ๋๋ค.
- AVA: ์๋์ ๋จ์์ฑ์ ์ค์ ์ ๋ ๋ฏธ๋๋ฉํ๊ณ ๋ ์์ ์ธ ํ ์คํธ ํ๋ ์์ํฌ์ ๋๋ค. ๋น๋๊ธฐ ํ ์คํธ๋ฅผ ์ฌ์ฉํ๋ฉฐ ๊นจ๋ํ๊ณ ์ฌ์ฉํ๊ธฐ ์ฌ์ด API๋ฅผ ์ ๊ณตํฉ๋๋ค.
- Tape: ๋จ์์ฑ๊ณผ ๊ฐ๋ ์ฑ์ ๊ฐ์กฐํ๋ ๊ฐ๋จํ๊ณ ๊ฐ๋ฒผ์ด ํ ์คํธ ํ๋ ์์ํฌ์ ๋๋ค. ์ต์ํ์ API๋ฅผ ๊ฐ์ง๊ณ ์์ด ๋ฐฐ์ฐ๊ณ ์ฌ์ฉํ๊ธฐ ์ฝ์ต๋๋ค.
๋จ์ ํ ์คํธ ์์ (Jest)
๋ ์ซ์๋ฅผ ๋ํ๋ ๊ฐ๋จํ ํจ์ ์์ ๋ฅผ ์ดํด๋ณด๊ฒ ์ต๋๋ค.
// add.js
function add(a, b) {
return a + b;
}
module.exports = add;
๋ค์์ Jest๋ฅผ ์ฌ์ฉํ ์ด ํจ์์ ๋ํ ๋จ์ ํ ์คํธ์ ๋๋ค.
// add.test.js
const add = require('./add');
test('1 + 2๋ฅผ ๋ํ๋ฉด 3์ด ๋๋ค', () => {
expect(add(1, 2)).toBe(3);
});
test('-1 + 1์ ๋ํ๋ฉด 0์ด ๋๋ค', () => {
expect(add(-1, 1)).toBe(0);
});
์ด ์์ ์์๋ Jest์ expect ํจ์๋ฅผ ์ฌ์ฉํ์ฌ add ํจ์์ ์ถ๋ ฅ์ ๋ํ ์ด์ค์
์ ๋ง๋ญ๋๋ค. toBe ๋งค์ฒ๋ ์ค์ ๊ฒฐ๊ณผ๊ฐ ์์ ๊ฒฐ๊ณผ์ ์ผ์นํ๋์ง ํ์ธํฉ๋๋ค.
ํตํฉ ํ ์คํธ
ํตํฉ ํ ์คํธ๋ ๋ฌด์์ธ๊ฐ?
ํตํฉ ํ ์คํธ๋ ์ฝ๋์ ๋ค๋ฅธ ๋จ์ ๋๋ ๊ตฌ์ฑ ์์ ๊ฐ์ ์ํธ ์์ฉ์ ํ ์คํธํ๋ ๊ฒ์ ํฌํจํฉ๋๋ค. ๊ฐ๋ณ ๋จ์๋ฅผ ๊ฒฉ๋ฆฌํ์ฌ ์ง์คํ๋ ๋จ์ ํ ์คํธ์ ๋ฌ๋ฆฌ, ํตํฉ ํ ์คํธ๋ ์ด๋ฌํ ๋จ์๋ค์ด ๊ฒฐํฉ๋์์ ๋ ์ฌ๋ฐ๋ฅด๊ฒ ํจ๊ป ์๋ํ๋์ง ํ์ธํฉ๋๋ค. ๋ชฉํ๋ ๋ชจ๋ ๊ฐ์ ๋ฐ์ดํฐ๊ฐ ์ฌ๋ฐ๋ฅด๊ฒ ํ๋ฅด๊ณ ์ ์ฒด ์์คํ ์ด ์์๋๋ก ์๋ํ๋์ง ํ์ธํ๋ ๊ฒ์ ๋๋ค.
ํตํฉ ํ ์คํธ์ ์ด์
- ์ํธ ์์ฉ ๊ฒ์ฆ: ํตํฉ ํ ์คํธ๋ ์์คํ ์ ๋ค๋ฅธ ๋ถ๋ถ๋ค์ด ํจ๊ป ์ฌ๋ฐ๋ฅด๊ฒ ์๋ํ๋์ง ํ์ธํฉ๋๋ค.
- ์ธํฐํ์ด์ค ์ค๋ฅ ๊ฐ์ง: ์ด ํ ์คํธ๋ ์๋ชป๋ ๋ฐ์ดํฐ ์ ํ์ด๋ ๋๋ฝ๋ ๋งค๊ฐ๋ณ์์ ๊ฐ์ ๋ชจ๋ ๊ฐ์ ์ธํฐํ์ด์ค ์ค๋ฅ๋ฅผ ์๋ณํ ์ ์์ต๋๋ค.
- ์ ๋ขฐ ๊ตฌ์ถ: ํตํฉ ํ ์คํธ๋ ์์คํ ์ ์ฒด๊ฐ ์ฌ๋ฐ๋ฅด๊ฒ ์๋ํ๊ณ ์๋ค๋ ํ์ ์ ์ค๋๋ค.
- ์ค์ ์๋๋ฆฌ์ค ํด๊ฒฐ: ํตํฉ ํ ์คํธ๋ ์ฌ๋ฌ ๊ตฌ์ฑ ์์๊ฐ ์ํธ ์์ฉํ๋ ์ค์ ์๋๋ฆฌ์ค๋ฅผ ์๋ฎฌ๋ ์ด์ ํฉ๋๋ค.
ํตํฉ ํ ์คํธ ์ ๋ต
ํตํฉ ํ ์คํธ์๋ ๋ค์๊ณผ ๊ฐ์ ์ฌ๋ฌ ์ ๋ต์ ์ฌ์ฉํ ์ ์์ต๋๋ค.
- ํํฅ์ ํ ์คํธ: ์ต์์ ๋ชจ๋์์ ์์ํ์ฌ ์ ์ฐจ ํ์ ์์ค ๋ชจ๋์ ํตํฉํฉ๋๋ค.
- ์ํฅ์ ํ ์คํธ: ์ตํ์ ๋ชจ๋์์ ์์ํ์ฌ ์ ์ฐจ ์์ ์์ค ๋ชจ๋์ ํตํฉํฉ๋๋ค.
- ๋น ๋ฑ ํ ์คํธ: ๋ชจ๋ ๋ชจ๋์ ํ ๋ฒ์ ํตํฉํ๋ ๋ฐฉ์์ผ๋ก, ์ํํ๊ณ ๋๋ฒ๊น ์ด ์ด๋ ค์ธ ์ ์์ต๋๋ค.
- ์๋์์น ํ ์คํธ: ํํฅ์๊ณผ ์ํฅ์ ํ ์คํธ ์ ๊ทผ ๋ฐฉ์์ ๊ฒฐํฉํฉ๋๋ค.
ํตํฉ ํ ์คํธ ๋๊ตฌ ๋ฐ ํ๋ ์์ํฌ
๋จ์ ํ ์คํธ์ ์ฌ์ฉ๋๋ ๋์ผํ ํ ์คํธ ํ๋ ์์ํฌ๋ฅผ ํตํฉ ํ ์คํธ์๋ ์ฌ์ฉํ ์ ์์ต๋๋ค. ๋ํ, ํนํ ์ธ๋ถ ์๋น์ค๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ฅผ ๋ค๋ฃฐ ๋ ํตํฉ ํ ์คํธ์ ๋์์ด ๋๋ ๋ช ๊ฐ์ง ์ ๋ฌธ ๋๊ตฌ๊ฐ ์์ต๋๋ค.
- Supertest: API ์๋ํฌ์ธํธ๋ฅผ ์ฝ๊ฒ ํ ์คํธํ ์ ์๊ฒ ํด์ฃผ๋ Node.js์ฉ ๊ณ ๊ธ HTTP ํ ์คํธ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ๋๋ค.
- Testcontainers: ํตํฉ ํ ์คํธ๋ฅผ ์ํด ๋ฐ์ดํฐ๋ฒ ์ด์ค, ๋ฉ์์ง ๋ธ๋ก์ปค ๋ฐ ๊ธฐํ ์๋น์ค์ ๊ฒฝ๋, ์ผํ์ฉ ์ธ์คํด์ค๋ฅผ ์ ๊ณตํ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ๋๋ค.
ํตํฉ ํ ์คํธ ์์ (Supertest)
์ธ์ฌ๋ง์ ๋ฐํํ๋ ๊ฐ๋จํ Node.js API ์๋ํฌ์ธํธ ์์ ๋ฅผ ์ดํด๋ณด๊ฒ ์ต๋๋ค.
// app.js
const express = require('express');
const app = express();
const port = 3000;
app.get('/greet/:name', (req, res) => {
res.send(`Hello, ${req.params.name}!`);
});
app.listen(port, () => {
console.log(`Example app listening at http://localhost:${port}`);
});
module.exports = app;
๋ค์์ Supertest๋ฅผ ์ฌ์ฉํ ์ด ์๋ํฌ์ธํธ์ ๋ํ ํตํฉ ํ ์คํธ์ ๋๋ค.
// app.test.js
const request = require('supertest');
const app = require('./app');
describe('GET /greet/:name', () => {
test('"Hello, John!"์ผ๋ก ์๋ตํด์ผ ํฉ๋๋ค', async () => {
const response = await request(app).get('/greet/John');
expect(response.statusCode).toBe(200);
expect(response.text).toBe('Hello, John!');
});
});
์ด ์์ ์์๋ Supertest๋ฅผ ์ฌ์ฉํ์ฌ /greet/:name ์๋ํฌ์ธํธ์ HTTP ์์ฒญ์ ๋ณด๋ด๊ณ ์๋ต์ด ์์๋๋ก์ธ์ง ํ์ธํฉ๋๋ค. ์ํ ์ฝ๋์ ์๋ต ๋ณธ๋ฌธ์ ๋ชจ๋ ํ์ธํ๊ณ ์์ต๋๋ค.
์๋ํฌ์๋(E2E) ํ ์คํธ
์๋ํฌ์๋(E2E) ํ ์คํธ๋ ๋ฌด์์ธ๊ฐ?
์๋ํฌ์๋(E2E) ํ ์คํธ๋ ์ค์ ์ฌ์ฉ์ ์ํธ ์์ฉ์ ์๋ฎฌ๋ ์ด์ ํ์ฌ ์ ์ฒด ์ ํ๋ฆฌ์ผ์ด์ ํ๋ฆ์ ์ฒ์๋ถํฐ ๋๊น์ง ํ ์คํธํ๋ ๊ฒ์ ํฌํจํฉ๋๋ค. ์ด ์ ํ์ ํ ์คํธ๋ ํ๋ก ํธ์๋, ๋ฐฑ์๋ ๋ฐ ๋ชจ๋ ์ธ๋ถ ์๋น์ค๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ฅผ ํฌํจํ ์์คํ ์ ๋ชจ๋ ๋ถ๋ถ์ด ํจ๊ป ์ฌ๋ฐ๋ฅด๊ฒ ์๋ํ๋์ง ํ์ธํฉ๋๋ค. ๋ชฉํ๋ ์ ํ๋ฆฌ์ผ์ด์ ์ด ์ฌ์ฉ์์ ๊ธฐ๋๋ฅผ ์ถฉ์กฑํ๊ณ ๋ชจ๋ ์ค์ํ ์ํฌํ๋ก์ฐ๊ฐ ์ฌ๋ฐ๋ฅด๊ฒ ์๋ํ๋์ง ํ์ธํ๋ ๊ฒ์ ๋๋ค.
E2E ํ ์คํธ์ ์ด์
- ์ค์ ์ฌ์ฉ์ ํ๋ ์๋ฎฌ๋ ์ด์ : E2E ํ ์คํธ๋ ์ฌ์ฉ์๊ฐ ์ ํ๋ฆฌ์ผ์ด์ ๊ณผ ์ํธ ์์ฉํ๋ ๋ฐฉ์์ ๋ชจ๋ฐฉํ์ฌ ๊ธฐ๋ฅ์ ๋ํ ํ์ค์ ์ธ ํ๊ฐ๋ฅผ ์ ๊ณตํฉ๋๋ค.
- ์ ์ฒด ์์คํ ๊ฒ์ฆ: ์ด ํ ์คํธ๋ ์ ์ฒด ์ ํ๋ฆฌ์ผ์ด์ ํ๋ฆ์ ๋ค๋ฃจ์ด ๋ชจ๋ ๊ตฌ์ฑ ์์๊ฐ ์ํํ๊ฒ ํจ๊ป ์๋ํ๋์ง ํ์ธํฉ๋๋ค.
- ํตํฉ ๋ฌธ์ ๊ฐ์ง: E2E ํ ์คํธ๋ ํ๋ก ํธ์๋์ ๋ฐฑ์๋์ ๊ฐ์ด ์์คํ ์ ๋ค๋ฅธ ๋ถ๋ถ ๊ฐ์ ํตํฉ ๋ฌธ์ ๋ฅผ ์๋ณํ ์ ์์ต๋๋ค.
- ํ์ ์ ๊ณต: E2E ํ ์คํธ๋ ์ ํ๋ฆฌ์ผ์ด์ ์ด ์ฌ์ฉ์ ๊ด์ ์์ ์ฌ๋ฐ๋ฅด๊ฒ ์๋ํ๊ณ ์๋ค๋ ๋์ ์์ค์ ํ์ ์ ์ ๊ณตํฉ๋๋ค.
E2E ํ ์คํธ ๋๊ตฌ ๋ฐ ํ๋ ์์ํฌ
E2E ํ ์คํธ๋ฅผ ์์ฑํ๊ณ ์คํํ๊ธฐ ์ํ ์ฌ๋ฌ ๋๊ตฌ์ ํ๋ ์์ํฌ๊ฐ ์์ต๋๋ค. ์ธ๊ธฐ ์๋ ๋ช ๊ฐ์ง ์ต์ ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
- Cypress: ๋น ๋ฅด๊ณ ์ ๋ขฐํ ์ ์๋ ํ ์คํธ ๊ฒฝํ์ ์ ๊ณตํ๋ ํ๋์ ์ด๊ณ ์ฌ์ฉ์ ์นํ์ ์ธ E2E ํ ์คํธ ํ๋ ์์ํฌ์ ๋๋ค. ์๊ฐ ์ฌํ ๋๋ฒ๊น , ์๋ ๋๊ธฐ ๋ฐ ์ค์๊ฐ ์๋ก๊ณ ์นจ ๊ธฐ๋ฅ์ด ์์ต๋๋ค.
- Selenium: ์ฌ๋ฌ ๋ธ๋ผ์ฐ์ ์ ํ๋ก๊ทธ๋๋ฐ ์ธ์ด๋ฅผ ์ง์ํ๋ ๋๋ฆฌ ์ฌ์ฉ๋๊ณ ๋ค์ฌ๋ค๋ฅํ ํ ์คํธ ํ๋ ์์ํฌ์ ๋๋ค. Cypress๋ณด๋ค ๋ ๋ง์ ๊ตฌ์ฑ์ด ํ์ํ์ง๋ง ๋ ํฐ ์ ์ฐ์ฑ์ ์ ๊ณตํฉ๋๋ค.
- Playwright: Microsoft์์ ๊ฐ๋ฐํ ๋น๊ต์ ์๋ก์ด E2E ํ ์คํธ ํ๋ ์์ํฌ๋ก, ์ฌ๋ฌ ๋ธ๋ผ์ฐ์ ๋ฅผ ์ง์ํ๊ณ ์น ํ์ด์ง์ ์ํธ ์์ฉํ๊ธฐ ์ํ ํ๋ถํ ๊ธฐ๋ฅ ์ธํธ๋ฅผ ์ ๊ณตํฉ๋๋ค.
- Puppeteer: Google์์ ๊ฐ๋ฐํ Node.js ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ก, ํค๋๋ฆฌ์ค Chrome ๋๋ Chromium์ ์ ์ดํ๊ธฐ ์ํ ๊ณ ๊ธ API๋ฅผ ์ ๊ณตํฉ๋๋ค. E2E ํ ์คํธ, ์น ์คํฌ๋ํ ๋ฐ ์๋ํ์ ์ฌ์ฉํ ์ ์์ต๋๋ค.
E2E ํ ์คํธ ์์ (Cypress)
Cypress๋ฅผ ์ฌ์ฉํ E2E ํ ์คํธ์ ๊ฐ๋จํ ์์ ๋ฅผ ์ดํด๋ณด๊ฒ ์ต๋๋ค. ์ฌ์ฉ์ ์ด๋ฆ๊ณผ ์ํธ ํ๋, ๊ทธ๋ฆฌ๊ณ ์ ์ถ ๋ฒํผ์ด ์๋ ๋ก๊ทธ์ธ ์์์ด ์๋ค๊ณ ๊ฐ์ ํด ๋ณด๊ฒ ์ต๋๋ค.
// login.test.js
describe('๋ก๊ทธ์ธ ์์', () => {
it('์ฑ๊ณต์ ์ผ๋ก ๋ก๊ทธ์ธํด์ผ ํฉ๋๋ค', () => {
cy.visit('/login');
cy.get('#username').type('testuser');
cy.get('#password').type('password123');
cy.get('button[type="submit"]').click();
cy.url().should('include', '/dashboard');
cy.contains('Welcome, testuser!').should('be.visible');
});
});
์ด ์์ ์์๋ Cypress ๋ช ๋ น์ ์ฌ์ฉํ์ฌ ๋ค์์ ์ํํฉ๋๋ค.
cy.visit('/login'): ๋ก๊ทธ์ธ ํ์ด์ง๋ฅผ ๋ฐฉ๋ฌธํฉ๋๋ค.cy.get('#username').type('testuser'): ์ฌ์ฉ์ ์ด๋ฆ ํ๋์ "testuser"๋ฅผ ์ ๋ ฅํฉ๋๋ค.cy.get('#password').type('password123'): ์ํธ ํ๋์ "password123"์ ์ ๋ ฅํฉ๋๋ค.cy.get('button[type="submit"]').click(): ์ ์ถ ๋ฒํผ์ ํด๋ฆญํฉ๋๋ค.cy.url().should('include', '/dashboard'): ์ฑ๊ณต์ ์ธ ๋ก๊ทธ์ธ ํ URL์ "/dashboard"๊ฐ ํฌํจ๋๋์ง ํ์ธํฉ๋๋ค.cy.contains('Welcome, testuser!').should('be.visible'): ํ์ ๋ฉ์์ง๊ฐ ํ์ด์ง์ ํ์๋๋์ง ํ์ธํฉ๋๋ค.
๋จ์ vs. ํตํฉ vs. E2E: ์์ฝ
๋ค์์ ๋จ์, ํตํฉ, E2E ํ ์คํธ ๊ฐ์ ์ฃผ์ ์ฐจ์ด์ ์ ์์ฝํ ํ์ ๋๋ค.
| ํ ์คํธ ์ ํ | ์ด์ | ๋ฒ์ | ์๋ | ๋น์ฉ | ๋๊ตฌ |
|---|---|---|---|---|---|
| ๋จ์ ํ ์คํธ | ๊ฐ๋ณ ๋จ์ ๋๋ ๊ตฌ์ฑ ์์ | ๊ฐ์ฅ ์์ | ๊ฐ์ฅ ๋น ๋ฆ | ๊ฐ์ฅ ๋ฎ์ | Jest, Mocha, Jasmine, AVA, Tape |
| ํตํฉ ํ ์คํธ | ๋จ์ ๊ฐ์ ์ํธ ์์ฉ | ์ค๊ฐ | ์ค๊ฐ | ์ค๊ฐ | Jest, Mocha, Jasmine, Supertest, Testcontainers |
| E2E ํ ์คํธ | ์ ์ฒด ์ ํ๋ฆฌ์ผ์ด์ ํ๋ฆ | ๊ฐ์ฅ ํผ | ๊ฐ์ฅ ๋๋ฆผ | ๊ฐ์ฅ ๋์ | Cypress, Selenium, Playwright, Puppeteer |
๊ฐ ํ ์คํธ ์ ํ์ ์ธ์ ์ฌ์ฉํด์ผ ํ๋๊ฐ
์ด๋ค ์ ํ์ ํ ์คํธ๋ฅผ ์ฌ์ฉํ ์ง๋ ํ๋ก์ ํธ์ ํน์ ์๊ตฌ ์ฌํญ์ ๋ฐ๋ผ ๋ค๋ฆ ๋๋ค. ๋ค์์ ์ผ๋ฐ์ ์ธ ์ง์นจ์ ๋๋ค.
- ๋จ์ ํ ์คํธ: ์ฝ๋์ ๋ชจ๋ ๊ฐ๋ณ ๋จ์ ๋๋ ๊ตฌ์ฑ ์์์ ๋ํด ๋จ์ ํ ์คํธ๋ฅผ ์ฌ์ฉํ์ธ์. ์ด๊ฒ์ด ํ ์คํธ ์ ๋ต์ ๊ธฐ์ด๊ฐ ๋์ด์ผ ํฉ๋๋ค.
- ํตํฉ ํ ์คํธ: ํนํ ์ธ๋ถ ์๋น์ค๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ฅผ ๋ค๋ฃฐ ๋ ๋ค๋ฅธ ๋จ์๋ ๊ตฌ์ฑ ์์๊ฐ ํจ๊ป ์ฌ๋ฐ๋ฅด๊ฒ ์๋ํ๋์ง ํ์ธํ๊ธฐ ์ํด ํตํฉ ํ ์คํธ๋ฅผ ์ฌ์ฉํ์ธ์.
- E2E ํ ์คํธ: ์ฌ์ฉ์ ๊ด์ ์์ ์ ์ฒด ์ ํ๋ฆฌ์ผ์ด์ ํ๋ฆ์ด ์ฌ๋ฐ๋ฅด๊ฒ ์๋ํ๋์ง ํ์ธํ๊ธฐ ์ํด E2E ํ ์คํธ๋ฅผ ์ฌ์ฉํ์ธ์. ์ค์ํ ์ํฌํ๋ก์ฐ์ ์ฌ์ฉ์ ์ฌ์ ์ ์ง์คํ์ธ์.
์ผ๋ฐ์ ์ธ ์ ๊ทผ ๋ฐฉ์์ ํ ์คํธ ํผ๋ผ๋ฏธ๋๋ฅผ ๋ฐ๋ฅด๋ ๊ฒ์ ๋๋ค. ์ด๋ ๋ค์์ ๋จ์ ํ ์คํธ, ์ ๋นํ ์์ ํตํฉ ํ ์คํธ, ์์์ E2E ํ ์คํธ๋ฅผ ๊ฐ์ง ๊ฒ์ ์ ์ํฉ๋๋ค.
ํ ์คํธ ํผ๋ผ๋ฏธ๋
ํ ์คํธ ํผ๋ผ๋ฏธ๋๋ ์ํํธ์จ์ด ํ๋ก์ ํธ์์ ๋ค๋ฅธ ์ ํ์ ํ ์คํธ์ ์ด์์ ์ธ ๋น์จ์ ๋ํ๋ด๋ ์๊ฐ์ ์์ ์ ๋๋ค. ์ด๋ ๋ค์์ ๊ฐ์ ธ์ผ ํจ์ ์ ์ํฉ๋๋ค.
- ๊ด๋ฒ์ํ ๊ธฐ๋ฐ์ ๋จ์ ํ ์คํธ: ์ด ํ ์คํธ๋ ๋น ๋ฅด๊ณ ์ ๋ ดํ๋ฉฐ ์ ์ง๋ณด์๊ฐ ์ฌ์ฐ๋ฏ๋ก ๋ง์ ์๋ฅผ ๊ฐ์ ธ์ผ ํฉ๋๋ค.
- ๋ ์์ ๊ณ์ธต์ ํตํฉ ํ ์คํธ: ์ด ํ ์คํธ๋ ๋จ์ ํ ์คํธ๋ณด๋ค ๋ ๋ณต์กํ๊ณ ๋น์ธ๋ฏ๋ก ๋ ์ ์ ์๋ฅผ ๊ฐ์ ธ์ผ ํฉ๋๋ค.
- ์ข์ ์ ์ ์ E2E ํ ์คํธ: ์ด ํ ์คํธ๋ ๊ฐ์ฅ ๋ณต์กํ๊ณ ๋น์ธ๋ฏ๋ก ๊ฐ์ฅ ์ ์ ์๋ฅผ ๊ฐ์ ธ์ผ ํฉ๋๋ค.
ํผ๋ผ๋ฏธ๋๋ ๋จ์ ํ ์คํธ๋ฅผ ์ฃผ์ ํ ์คํธ ํํ๋ก ์ง์คํ๋ ๊ฒ์ ์ค์์ฑ์ ๊ฐ์กฐํ๋ฉฐ, ํตํฉ ๋ฐ E2E ํ ์คํธ๋ ์ ํ๋ฆฌ์ผ์ด์ ์ ํน์ ์์ญ์ ๋ํ ์ถ๊ฐ์ ์ธ ์ปค๋ฒ๋ฆฌ์ง๋ฅผ ์ ๊ณตํฉ๋๋ค.
ํ ์คํธ์ ๋ํ ๊ธ๋ก๋ฒ ๊ณ ๋ ค์ฌํญ
๊ธ๋ก๋ฒ ๊ณ ๊ฐ์ ์ํ ์ํํธ์จ์ด๋ฅผ ๊ฐ๋ฐํ ๋ ํ ์คํธ ์ค์ ๋ค์ ์์๋ฅผ ๊ณ ๋ คํ๋ ๊ฒ์ด ์ค์ํฉ๋๋ค.
- ํ์งํ(L10n): ํ ์คํธ, ๋ ์ง, ํตํ ๋ฐ ๊ธฐํ ๋ก์ผ์ผ๋ณ ์์๊ฐ ์ฌ๋ฐ๋ฅด๊ฒ ํ์๋๋์ง ํ์ธํ๊ธฐ ์ํด ๋ค๋ฅธ ์ธ์ด ๋ฐ ์ง์ญ ์ค์ ์ผ๋ก ์ ํ๋ฆฌ์ผ์ด์ ์ ํ ์คํธํ์ธ์. ์๋ฅผ ๋ค์ด, ๋ ์ง ํ์์ด ์ฌ์ฉ์ ์ง์ญ์ ๋ฐ๋ผ ํ์๋๋์ง ํ์ธํฉ๋๋ค(์: ๋ฏธ๊ตญ์์๋ MM/DD/YYYY, ์ ๋ฝ์์๋ DD/MM/YYYY).
- ๊ตญ์ ํ(I18n): ์ ํ๋ฆฌ์ผ์ด์ ์ด ๋ค๋ฅธ ๋ฌธ์ ์ธ์ฝ๋ฉ(์: UTF-8)์ ์ง์ํ๊ณ ๋ค์ํ ์ธ์ด์ ํ ์คํธ๋ฅผ ์ฒ๋ฆฌํ ์ ์๋์ง ํ์ธํ์ธ์. ์ค๊ตญ์ด, ์ผ๋ณธ์ด, ํ๊ตญ์ด์ ๊ฐ์ด ๋ค๋ฅธ ๋ฌธ์ ์งํฉ์ ์ฌ์ฉํ๋ ์ธ์ด๋ก ํ ์คํธํ์ธ์.
- ์๊ฐ๋: ์ ํ๋ฆฌ์ผ์ด์ ์ด ์๊ฐ๋ ๋ฐ ์ผ๊ด ์ ์ฝ ์๊ฐ์ ์ด๋ป๊ฒ ์ฒ๋ฆฌํ๋์ง ํ ์คํธํ์ธ์. ๋ค๋ฅธ ์๊ฐ๋์ ์ฌ์ฉ์์๊ฒ ๋ ์ง์ ์๊ฐ์ด ์ฌ๋ฐ๋ฅด๊ฒ ํ์๋๋์ง ํ์ธํ์ธ์.
- ํตํ: ์ ํ๋ฆฌ์ผ์ด์ ์ด ๊ธ์ต ๊ฑฐ๋๋ฅผ ํฌํจํ๋ ๊ฒฝ์ฐ ์ฌ๋ฌ ํตํ๋ฅผ ์ง์ํ๊ณ ํตํ ๊ธฐํธ๊ฐ ์ฌ์ฉ์ ๋ก์ผ์ผ์ ๋ฐ๋ผ ์ฌ๋ฐ๋ฅด๊ฒ ํ์๋๋์ง ํ์ธํ์ธ์.
- ์ ๊ทผ์ฑ: ์ฅ์ ๊ฐ ์๋ ์ฌ๋๋ค๋ ์ฌ์ฉํ ์ ์๋๋ก ์ ํ๋ฆฌ์ผ์ด์ ์ ์ ๊ทผ์ฑ์ ํ ์คํธํ์ธ์. WCAG(์น ์ฝํ ์ธ ์ ๊ทผ์ฑ ๊ฐ์ด๋๋ผ์ธ)์ ๊ฐ์ ์ ๊ทผ์ฑ ๊ฐ์ด๋๋ผ์ธ์ ๋ฐ๋ฅด์ธ์.
- ๋ฌธํ์ ๋ฏผ๊ฐ์ฑ: ๋ฌธํ์ ์ฐจ์ด๋ฅผ ์ ๋ ํ๊ณ ํน์ ๋ฌธํ์์ ๋ถ์พํ๊ฑฐ๋ ๋ถ์ ์ ํ ์ ์๋ ์ด๋ฏธ์ง, ์์ง ๋๋ ์ธ์ด ์ฌ์ฉ์ ํผํ์ธ์.
- ๋ฒ๋ฅ ์ค์: ๋ฐ์ดํฐ ํ๋ผ์ด๋ฒ์ ๋ฒ(์: GDPR) ๋ฐ ์ ๊ทผ์ฑ ๋ฒ(์: ADA)๊ณผ ๊ฐ์ด ์ฌ์ฉ๋ ๊ตญ๊ฐ์ ๋ชจ๋ ๊ด๋ จ ๋ฒ๋ฅ ๋ฐ ๊ท์ ์ ์ ํ๋ฆฌ์ผ์ด์ ์ด ์ค์ํ๋์ง ํ์ธํ์ธ์.
๊ฒฐ๋ก
์ฌ๋ฐ๋ฅธ ํ ์คํธ ์ ๋ต์ ์ ํํ๋ ๊ฒ์ ๊ฒฌ๊ณ ํ๊ณ ์ ๋ขฐํ ์ ์๋ ์๋ฐ์คํฌ๋ฆฝํธ ์ ํ๋ฆฌ์ผ์ด์ ์ ๊ตฌ์ถํ๋ ๋ฐ ํ์์ ์ ๋๋ค. ๋จ์ ํ ์คํธ, ํตํฉ ํ ์คํธ, E2E ํ ์คํธ๋ ๊ฐ๊ฐ ์ฝ๋ ํ์ง์ ๋ณด์ฅํ๋ ๋ฐ ์ค์ํ ์ญํ ์ ํฉ๋๋ค. ์ด๋ฌํ ํ ์คํธ ์ ํ ๊ฐ์ ์ฐจ์ด์ ์ ์ดํดํ๊ณ ๋ชจ๋ฒ ์ฌ๋ก๋ฅผ ๋ฐ๋ฅด๋ฉด ํ๋ก์ ํธ์ ํน์ ์๊ตฌ์ ๋ง๋ ํฌ๊ด์ ์ธ ํ ์คํธ ์ ๋ต์ ๋ง๋ค ์ ์์ต๋๋ค. ์ ์ธ๊ณ ๊ณ ๊ฐ์ ์ํ ์ํํธ์จ์ด๋ฅผ ๊ฐ๋ฐํ ๋๋ ํ์งํ, ๊ตญ์ ํ, ์ ๊ทผ์ฑ๊ณผ ๊ฐ์ ๊ธ๋ก๋ฒ ์์๋ฅผ ๊ณ ๋ คํ๋ ๊ฒ์ ์์ง ๋ง์ธ์. ํ ์คํธ์ ํฌ์ํจ์ผ๋ก์จ ๋ฒ๊ทธ๋ฅผ ์ค์ด๊ณ ์ฝ๋ ํ์ง์ ๊ฐ์ ํ๋ฉฐ ์ฌ์ฉ์ ๋ง์กฑ๋๋ฅผ ๋์ผ ์ ์์ต๋๋ค.